package com.cloudcross.ssp.service.impl;

import java.io.IOException;
import java.sql.ResultSet;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.adinall.dsp.core.db.DBHelper;
import com.adinall.dsp.core.utils.NumberUtils;
import com.cloudcross.ssp.base.dao.GenericIBatisDao;
import com.cloudcross.ssp.base.web.result.AjaxResult;
import com.cloudcross.ssp.common.Config;
import com.cloudcross.ssp.common.consts.BusinessConstants;
import com.cloudcross.ssp.common.consts.DirectType;
import com.cloudcross.ssp.common.utils.AdvertiserSortByDate;
import com.cloudcross.ssp.common.utils.Assert;
import com.cloudcross.ssp.common.utils.Common;
import com.cloudcross.ssp.common.utils.DateUtils;
import com.cloudcross.ssp.common.utils.DoublePreciseCompute;
import com.cloudcross.ssp.common.utils.HttpClienUtil;
import com.cloudcross.ssp.common.utils.MapBuilder;
import com.cloudcross.ssp.common.utils.Pager;
import com.cloudcross.ssp.common.utils.SqlHelper;
import com.cloudcross.ssp.model.Account;
import com.cloudcross.ssp.model.AdGroup;
import com.cloudcross.ssp.model.AdGroupNum;
import com.cloudcross.ssp.model.AdGroupZoneConvert;
import com.cloudcross.ssp.model.AdgroupZone;
import com.cloudcross.ssp.model.AdsVoEntity;
import com.cloudcross.ssp.model.Banner;
import com.cloudcross.ssp.model.CategoryEntity;
import com.cloudcross.ssp.model.CityCode;
import com.cloudcross.ssp.model.DayParting;
import com.cloudcross.ssp.model.Direct;
import com.cloudcross.ssp.model.Log;
import com.cloudcross.ssp.model.PlatFormParam;
import com.cloudcross.ssp.service.IAdGroupNumService;
import com.cloudcross.ssp.service.IAdGroupService;
import com.cloudcross.ssp.service.IAdgroupZoneService;
import com.cloudcross.ssp.service.IBannerService;
import com.cloudcross.ssp.service.ICityCodeService;
import com.cloudcross.ssp.service.IDirectService;
import com.cloudcross.ssp.service.ILogService;
import com.cloudcross.ssp.web.widget.SelectorController.ISelector;
import com.cloudcross.ssp.web.widget.SelectorController.ISelectorProvider;
import com.cloudcross.util.SqlServer;
import com.cloudcross.util.array.IntArray;
import com.google.gson.Gson;

@Service
public class AdGroupService implements IAdGroupService, ISelectorProvider {

    private static Logger logger = LogManager.getLogger(AdGroupService.class.getName());

    @Autowired
    private GenericIBatisDao myBatisDao;
    @Autowired
    private IDirectService directService;
    @Autowired
    private IBannerService bannerService;
    @Autowired
    private IAdgroupZoneService adgroupZoneService;
    @Autowired
    private ILogService logService;
    @Autowired
    Config config;
    @Autowired
    private ICityCodeService cityCodeService;

    @Autowired
    private IAdGroupNumService adGroupNumService;
    @Autowired
    private WebsiteService websiteService;

    @Override
    public AdGroup findById(Long id) {
        return myBatisDao.get("adGroupSqlMapper.findById", id);
    }

    @Override
    public int countByParams(Map<String, Object> paramMap) {
        return myBatisDao.get("adGroupSqlMapper.countByParams", paramMap);
    }

    @Override
    public List<AdGroup> findByParams(Map<String, Object> paramMap, Pager pager) {
        paramMap.put("pager", pager);
        return myBatisDao.getList("adGroupSqlMapper.findByParams", paramMap);
    }

    @Override
    public boolean add(AdGroup t) {
        myBatisDao.save("adGroupSqlMapper.addAdGroup", t);
        return true;
    }

    @Override
    public boolean edit(AdGroup t) {
        myBatisDao.save("adGroupSqlMapper.editAdGroup", t);
        return true;
    }

    @Override
    public boolean updateStatus(List<Long> idList, int status) {
        myBatisDao.save("adGroupSqlMapper.updateAdGroupStatus",
                MapBuilder.create(HashMap.class).add("status", status).add("idList", idList).add("updated", new Date()).map());
        return true;
    }

    @Override
    public List<AdGroup> findByOrderId(Long orderId) {
        return myBatisDao.getList("adGroupSqlMapper.findByOrderId", orderId);
    }

    @Override
    public boolean save(AdGroup adGroup, Map<String, Object> targetParamsMap, HttpServletRequest request, Account account) {
        try {
            MapBuilder mapBuilder = MapBuilder.create(HashMap.class).add("adGroup", adGroup);
            // 创建策略
            add(adGroup);
            // 设置媒体
            commonSaveMedia(targetParamsMap, mapBuilder.add("uiKey", "mediaObj").add("uiType", DirectType.mediaType).map(), request, account);
            // 定量设置
            commonSaveQuantity(targetParamsMap, mapBuilder.add("uiKey", "quantityObj").add("uiType", DirectType.quantityType).map());
            // adx设置
            commonSaveAdx(targetParamsMap, mapBuilder.add("uiKey", "adxObj").add("uiType", DirectType.adxType).map(), request, account);
            // 地域定向
            commonSaveDriect(targetParamsMap, mapBuilder.add("uiKey", "areas").add("uiType", DirectType.locateType).map(), 1);
            // 时间定向
            commonSaveDriect(targetParamsMap, mapBuilder.add("uiKey", "sdayParting").add("uiType", DirectType.timeType).map(), 1);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 保存ADX媒体
     */
    private void commonSaveAdx(Map<String, Object> targetParamsMap, Map<String, Object> map, HttpServletRequest request, Account account) {
        AdGroup adGroup = (AdGroup) map.get("adGroup");
        ObjectMapper objectMapper = new ObjectMapper();
        String objectToJson = String.valueOf(targetParamsMap.get("adxObj"));
        if (!StringUtils.isEmpty(objectToJson)) {
            try {
                AdGroupZoneConvert zoneList = objectMapper.readValue(objectToJson, AdGroupZoneConvert.class);
                List<AdgroupZone> groupZoneList = new ArrayList<AdgroupZone>();
                List<Long> adids = zoneList.getAdids();
                IntArray newIDs = new IntArray(10);
                Long adgroupId = adGroup.getId();
                Long supdated = System.currentTimeMillis();
                // 伪删除
                map.put("adgroupId", adgroupId);
                map.put("supdated", supdated);
                adgroupZoneService.updateAdxZoneIdByAdgroupId(map);
                if (!CollectionUtils.isEmpty(adids)) {
                    for (Long zone : adids) {
                        AdgroupZone adgroupZone = new AdgroupZone();
                        adgroupZone.setZoneId(zone);
                        adgroupZone.setAdgroupId(adGroup.getId());
                        adgroupZone.setStatus(1);
                        adgroupZone.setSupdated(System.currentTimeMillis() / 1000);
                        groupZoneList.add(adgroupZone);
                        newIDs.add(zone.intValue());
                    }
                    websiteService.insertGroupZone(groupZoneList);
                }
                String sNew = newIDs.toString();
                Log log = new Log();
                log.setActionType("修改ADX媒体");
                log.setTableName("t_adgroup");
                log.setRecordId(adGroup.getId());
                log.setActionTime("100");
                log.setAccountId(new Long(account.getId()));
                log.setUserIp(Common.toIpAddr(request));
                log.setAccountName(account.getAccountName());
                log.setModule("AdGroupZone");
                String action = "广告位变更为" + sNew;
                log.setAction(action);
                logService.add(log);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 保存聚告媒体
     */
    private void commonSaveMedia(Map<String, Object> targetParamsMap, Map<String, Object> map, HttpServletRequest request, Account account) {
        AdGroup adGroup = (AdGroup) map.get("adGroup");
        Integer deviceType = adGroup.getDeviceType();
        ObjectMapper objectMapper = new ObjectMapper();
        String manageDomain = config.getManageDomain();
        String mobileDomain = config.getAppDomain();
        String objectToJson = String.valueOf(targetParamsMap.get("mediaObj"));
        if (!StringUtils.isEmpty(objectToJson)) {
            try {
                AdGroupZoneConvert zoneList = objectMapper.readValue(objectToJson, AdGroupZoneConvert.class);
                List<AdgroupZone> groupZoneList = new ArrayList<AdgroupZone>();
                List<Long> adids = zoneList.getAdids();
                // 以前的广告位集合
                IntArray newIDs = new IntArray(10);
                Long adgroupId = adGroup.getId();
                Long supdated = System.currentTimeMillis() / 1000;
                // 伪删除
                map.put("adgroupId", adgroupId);
                map.put("supdated", supdated);
                map.put("deviceType", deviceType);
                adgroupZoneService.updateZoneIdByAdgroupId(map);
                if (!CollectionUtils.isEmpty(adids)) {
                    for (Long zone : adids) {
                        AdgroupZone adgroupZone = new AdgroupZone();
                        adgroupZone.setZoneId(zone);
                        adgroupZone.setAdgroupId(adGroup.getId());
                        adgroupZone.setStatus(1);
                        adgroupZone.setSupdated(System.currentTimeMillis() / 1000);
                        groupZoneList.add(adgroupZone);
                        if (deviceType == 1 || deviceType == 2) {
                            // 更改直客顺序
                            noticeDirectOrder(manageDomain + "media/updateDirectOrder.do?adid=" + zone + "&state=1");
                        } else if (deviceType == 3) {
                            noticeDirectOrder(mobileDomain + "direct/updateDirectOrder.do?token=U2FsdGVkX18FaI4Z08yvcLB9WHQPTXbL0EnLZ4bCIo&adid="
                                    + zone + "&status=1");
                        }
                        newIDs.add(zone.intValue());
                    }
                    websiteService.insertGroupZone(groupZoneList);
                }
                String sNew = newIDs.toString();
                Log log = new Log();
                log.setActionType("修改聚告媒体");
                log.setTableName("t_adgroup");
                log.setRecordId(adGroup.getId());
                log.setActionTime("100");
                log.setAccountId(new Long(account.getId()));
                log.setUserIp(Common.toIpAddr(request));
                log.setAccountName(account.getAccountName());
                log.setModule("AdGroupZone");
                String action = "广告位变更为" + sNew;
                log.setAction(action);
                logService.add(log);
                adGroup.setIsEdit(1);
                updateIsEdit(adGroup);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void commonSaveQuantity(Map<String, Object> targetParamsMap, Map<String, Object> map) {
        AdGroup adGroup = (AdGroup) map.get("adGroup");
        ObjectMapper objectMapper = new ObjectMapper();
        String objectToJson = String.valueOf(targetParamsMap.get("quantityObj"));
        List<Map<String, Object>> paramMaps;
        List<AdGroupNum> quantityList = new ArrayList<AdGroupNum>();
        if (!StringUtils.isEmpty(objectToJson)) {
            try {
                paramMaps = objectMapper.readValue(objectToJson, List.class);
                deleteAdgroupNumById(adGroup.getId());
                for (Map<String, Object> obj : paramMaps) {
                    AdGroupNum adGroupNum = new AdGroupNum();
                    adGroupNum.setAdgroupId(adGroup.getId());
                    adGroupNum.setClick(Integer.parseInt(ConvertUtils.convert(obj.get("click"))));
                    adGroupNum.setShow(Integer.parseInt(ConvertUtils.convert(obj.get("show"))));
                    adGroupNum.setDate(DateUtils.getString2ShortDate(String.valueOf(obj.get("date"))));
                    quantityList.add(adGroupNum);
                }
                insertAdGroupNumList(quantityList);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean edit(AdGroup adGroup, Map<String, Object> targetParamsMap, HttpServletRequest request, Account account) {
        edit(adGroup);
        /**
         * 时段定向的数据更新
         */
        // 处理带定向的问题
        MapBuilder mapBuilder = MapBuilder.create(HashMap.class).add("adGroup", adGroup);
        // 地域定向
        commonSaveDriect(targetParamsMap, mapBuilder.add("uiKey", "areas").add("uiType", DirectType.locateType).map(), 2);
        // 时间定向
        commonSaveDriect(targetParamsMap, mapBuilder.add("uiKey", "sdayParting").add("uiType", DirectType.timeType).map(), 2);
        // 媒体
        commonSaveMedia(targetParamsMap, mapBuilder.add("uiKey", "mediaObj").add("uiType", DirectType.mediaType).map(), request, account);
        // 定量设置
        commonSaveQuantity(targetParamsMap, mapBuilder.add("uiKey", "quantityObj").add("uiType", DirectType.quantityType).map());
        // adx设置
        commonSaveAdx(targetParamsMap, mapBuilder.add("uiKey", "adxObj").add("uiType", DirectType.adxType).map(), request, account);
        return true;
    }

    @Override
    public List<AdGroup> findByParams(Map<String, Object> paramMap) {
        return myBatisDao.getList("adGroupSqlMapper.findByParams1", paramMap);
    }

    @Override
    public List<Long> findAllAdGroudByAdvertiserId(Long advertiserId) {
        return myBatisDao.getList("adGroupSqlMapper.findAllAdGroudByAdvertiserId", advertiserId);
    }

    @Override
    public boolean updateSupdatedByAdvertiserId(List<Long> advertiserIdList, Date date) {
        myBatisDao.save("adGroupSqlMapper.updateSupdatedByAdvertiserID",
                MapBuilder.create(HashMap.class).add("advertiserIdList", advertiserIdList).add("modifyDate", date).map());
        return true;
    }

    @Override
    public boolean updateSupdatedByOrderId(List<Long> orderIdList, Date date) {
        myBatisDao.save("adGroupSqlMapper.updateSupdatedByOrderId",
                MapBuilder.create(HashMap.class).add("orderIdList", orderIdList).add("modifyDate", date).map());
        return true;
    }

    @Override
    public boolean updateStatusByAdvertiserId(List<Long> advertiserIdList, int status) {
        myBatisDao.save("adGroupSqlMapper.updateStatusByAdvertiserId",
                MapBuilder.create(HashMap.class).add("advertiserIdList", advertiserIdList).add("modifyDate", new Date()).add("status", status).map());
        return true;
    }

    @Override
    public boolean updateStatusByOrderId(List<Long> orderIdList, int status) {
        myBatisDao.save("adGroupSqlMapper.updateStatusByOrderId",
                MapBuilder.create(HashMap.class).add("orderIdList", orderIdList).add("modifyDate", new Date()).add("status", status).map());
        return true;
    }

    @Override
    public boolean updateStatusAll(List<Long> adGroupIdList, int status) {
        Boolean adGroupFlag = updateStatus(adGroupIdList, status);
        Boolean bannerFlag = this.bannerService.updateStatusByAdGroupId(adGroupIdList, status);
        return adGroupFlag && bannerFlag;
    }

    @Override
    public Map findAreasBack(Long adGroupId) {
        return myBatisDao.get("adGroupSqlMapper.findAreasBack", adGroupId);
    }

    @Override
    public Map<String, List<? extends ISelector>> provideData(String[] parentId) {
        Assert.isTrue(ArrayUtils.isNotEmpty(parentId));
        String orderId = parentId[0];
        List<AdGroup> adGroupList = findByOrderId(Long.parseLong(orderId));
        return MapBuilder.create(HashMap.class).add("adGroupList", adGroupList).map();
    }

    /**
     * @param targetParamsMap
     * @param map
     * @param type            == 1 add type == 2 update
     */
    public void commonSaveDriect(Map<String, Object> targetParamsMap, Map<String, Object> map, int type) {
        String uiKey = (String) map.get("uiKey");
        Integer uiType = (Integer) map.get("uiType");
        AdGroup adGroup = (AdGroup) map.get("adGroup");
        Direct direct = new Direct();
        direct.setAdGroupId(adGroup.getId());
        direct.setDirectType(uiType);
        if (targetParamsMap != null && targetParamsMap.containsKey(uiKey) && !targetParamsMap.get(uiKey).equals("")
                && !targetParamsMap.get(uiKey).equals("[]")) {
            // 添加地域 t_traget_show
            // 将地域定向的数据转化为后台需要的数据格式
            if (uiType == DirectType.locateType) {
                direct.setBackShow((String) targetParamsMap.get(uiKey));
                direct.setData(front2dblocate((String) targetParamsMap.get(uiKey)));
            }
            if (uiType == DirectType.timeType) {
                List<DayParting> dpList = getDayPartingList((String) targetParamsMap.get(uiKey));
                direct.setData(timeShow2Data(dpList));
                direct.setBackShow(timeShow(dpList));
            }
            direct.setUpdated(System.currentTimeMillis() / 1000);
            if (type == 1) {
                myBatisDao.save("directSqlMapper.addDirect", direct);
            } else if (type == 2) {
                myBatisDao.save("directSqlMapper.deleteDirect", direct);
                myBatisDao.save("directSqlMapper.addDirect", direct);
            }
        } else {
            if (type == 2) {
                myBatisDao.save("directSqlMapper.deleteDirect", direct);
            }
        }
    }

    /**
     * 地域定向 targetshow ===> targetdata [省名称|市ID]{1,n} ===> [市ID|]{1,n}
     * 把前台获取的数据转化成后台数据库需要的数据格式 CN|/CNXAXA00|CNSHSH00|CNBJBJ00|CNAHHZ00/
     */
    private String front2dblocate(String str) {
        if (null != str) {
            StringBuilder sb = new StringBuilder();
            String[] strArr = str.split(",");
            for (String tmp : strArr) {
                if (!NumberUtils.isNum(tmp)) {
                    List<CityCode> list = cityCodeService.queryCityCodeListByCn(tmp);
                    for (CityCode locate : list) {
                        sb.append(locate.getId() + "|");
                    }
                } else {
                    sb.append(tmp + "|");
                }
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * 时间定向
     * [{"startDate":"","dehours":"","endDate":""},{"startDate":"","dehours"
     * :"","endDate":""}] ===> startDate_dehours_endDate
     * [{"startDate":"2017-02-27","dehours":
     * "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23"
     * ,"endDate":"2017-02-27"}] ===> 2017-02-
     * 27_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23,2017-02-
     * 28_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23
     *
     * @param str
     * @return
     * @Asia/Shanghai
     */
    private List<DayParting> getDayPartingList(String str) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 获得前端传递过来的已选择时间段
        // String sdayParting = (String) paramMap.get("sdayParting");
        // 用来存储转换结果的JSONArray
        List<DayParting> dayList = new ArrayList<DayParting>();

        // 默认24个时间点
        String allHours = "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23";
        try {
            // 传过来已选择的时间JSONArray
            JSONArray jsonArray = new JSONArray(str);
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject object = jsonArray.getJSONObject(i);
                DayParting day = new DayParting();

                try {
                    Date startTemp = sdf.parse(object.getString("startDate"));
                    Date endTemp = sdf.parse(object.getString("endDate"));
                    // 此处可添加时间范围验证
                    day.setStartDate(startTemp);
                    day.setEndDate(endTemp);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                // 如果传过来的dehours是-1或空或者是空字符串，表示全选
                if (null == object.get("dehours") || "-1".equals(String.valueOf(object.getString("dehours")))
                        || "".equals(String.valueOf(object.getString("dehours")))) {
                    day.setDehours(allHours);
                } else {
                    day.setDehours(object.getString("dehours"));
                }

                dayList.add(day);
            }
            // 按照开始时间的先后顺序给dayList进行排序，排序后，比较相邻的2个时间段，能够得出未选择的时间段
            Collections.sort(dayList, new AdvertiserSortByDate());

        } catch (JSONException e) {
            logger.info("排期日期解析错误");
            e.printStackTrace();
        }
        return dayList;
    }

    private String timeShow(List<DayParting> dayList) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 用来存储转换结果的JSONArray
        JSONArray result = new JSONArray();
        for (int i = 0; i < dayList.size(); i++) {
            DayParting dayP = dayList.get(i);
            JSONObject object = new JSONObject();
            try {
                object.put("startDate", sdf.format(dayP.getStartDate()));
                object.put("endDate", sdf.format(dayP.getEndDate()));
                // 将已选择的时间段放入result中
                object.put("dehours", dayP.getDehours());
            } catch (JSONException e) {
                e.printStackTrace();
            }
            result.put(object);
        }
        return result.toString();
    }

    private String timeShow2Data(List<DayParting> dayList) {

        List<String> dpStr = new ArrayList<String>();
        for (int i = 0; i < dayList.size(); i++) {
            DayParting dp = dayList.get(i);
            if (!isStartBeforeEndDate(dp.getStartDate(), dp.getEndDate())) {
                continue;
            }
            String str = scheduleRoleStr(dayList.get(i).getStartDate(), dayList.get(i).getEndDate(), dayList.get(i).getDehours());
            dpStr.add(str);

        }
        String data = StringUtils.join(dpStr.toArray(), ",");
        if (data != null && data.trim() != "") {
            data = data.concat("@Asia/Shanghai");
        }
        return data;
    }

    private String scheduleRoleStr(Date startDate, Date endDate, String dehours) {
        List<Date> dateList = getStartDates(startDate, endDate);
        List<String> dataStr = new ArrayList<String>();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        String[] hours = dehours.split(",");
        for (Date date : dateList) {
            String s = sf.format(date);
            for (int i = 0; i < hours.length; i++) {
                String hour = hours[i];
                s = s.concat("_").concat(hour);
            }
            dataStr.add(s);
        }
        String returnStr = StringUtils.join(dataStr.toArray(), ",");
        return returnStr;
    }

    private boolean isStartBeforeEndDate(Date start, Date end) {
        if (start != null && end != null) {
            if (start.getTime() <= end.getTime()) {
                return true;
            }
        }
        return false;
    }

    public List<Date> getStartDates(Date dBegin, Date dEnd) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            dBegin = sf.parse(sf.format(dBegin));
            dEnd = sf.parse(sf.format(dEnd));
        } catch (ParseException e) {
            return null;
        }
        List<Date> lDate = new ArrayList<Date>();
        lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            lDate.add(calBegin.getTime());
        }
        return lDate;
    }

    @Override
    public int countByParamsBack(Map<String, Object> paramMap) {
        // 这里的搜索只是对投放名称进行搜索
        String searchValue = SqlHelper.doLike(paramMap.get("adGroupName"));
        paramMap.put("adGroupName", searchValue);
        return myBatisDao.get("adGroupSqlMapper.countByParamsBack", paramMap);
    }

    @Override
    public List<AdGroup> findByParamsBack(Map<String, Object> paramMap, Pager pager) {
        // 这里的搜索只是对投放名称进行搜索
        String searchValue = SqlHelper.doLike(paramMap.get("adGroupName"));
        paramMap.put("adGroupName", searchValue);
        paramMap.put("pager", pager);
        return myBatisDao.getList("adGroupSqlMapper.findByParams", paramMap);
    }

    @Override
    public boolean updateAdgroupZone(AdGroup adGroup, Map<String, Object> condition) {
        Long adgroupId = adGroup.getId();
        Long supdated = System.currentTimeMillis() / 1000;
        // 伪删除
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("adgroupId", adgroupId);
        map.put("supdated", supdated);
        adgroupZoneService.updateZoneIdByAdgroupId(map);

        // 添加投放与广告位对应关系
        String zoneIdStr = String.valueOf(condition.get("zoneId"));
        if (zoneIdStr != null && zoneIdStr != "") {
            String[] zoneId = zoneIdStr.split(",");
            AdgroupZone adgroupZone = new AdgroupZone();
            for (int i = 0; i < zoneId.length; i++) {
                adgroupZone.setAdgroupId(adgroupId);
                adgroupZone.setStatus(0);
                adgroupZone.setSupdated(supdated);
                adgroupZone.setZoneId(Long.valueOf(zoneId[i]).longValue());
                this.adgroupZoneService.saveAdgroupZone(adgroupZone);
            }
        }
        return true;
    }

    @Override
    public List<AdGroup> queryAdGroupByCondition(Map<String, Object> paramMap, Pager pager) {
        if (pager == null) {
            return myBatisDao.getList("adGroupSqlMapper.queryAdGroupExportByCondition", paramMap);
        } else {
            paramMap.put("pager", pager);
            return myBatisDao.getList("adGroupSqlMapper.queryAdGroupByCondition", paramMap);
        }
    }

    @Override
    public Integer queryAdGroupCountByCondition(Map<String, Object> paramMap) {
        return myBatisDao.get("adGroupSqlMapper.queryAdGroupCountByCondition", paramMap);
    }

    @Override
    public void saveAllOperator(AdGroup adGroup, Map<String, Object> condition, HttpServletRequest request, Account account) {
        save(adGroup, condition, request, account);
    }

    public void saveZone(AdGroup adGroup, Map<String, Object> condition) {
        Long supdated = System.currentTimeMillis();
        AdgroupZone adgroupZone = new AdgroupZone();
        adgroupZone.setAdgroupId(adGroup.getId());
        adgroupZone.setStatus(0);
        adgroupZone.setSupdated(supdated);

        String zoneId = String.valueOf(condition.get("zoneId"));
        List<Long> zoneIdList = new ArrayList<Long>();
        String[] zoneIdStr = zoneId.split(",");
        for (int i = 0; i < zoneIdStr.length; i++) {
            zoneIdList.add(Long.parseLong(zoneIdStr[i].trim()));
        }
        adgroupZoneService.saveAdgroupZoneList(adgroupZone, zoneIdList);
    }

    @Override
    public boolean saveUpdateAdgroup(AdGroup adGroup, Map<String, Object> paramMap, HttpServletRequest request, Account account) {
        // 日志
        Log log = new Log();
        log.setModule("AdGroup");
        log.setTableName("t_adgroup");
        log.setRecordId(adGroup.getId());
        log.setActionType("修改");
        log.setActionTime("100");
        log.setAccountId(new Long(account.getId()));
        log.setUserIp(Common.toIpAddr(request));
        log.setAccountName(account.getAccountName());
        // 先得到保存前的投放信息，以便于判断哪些做了修改
        Long adgroupId = adGroup.getId();
        // 投放主信息
        AdGroup formerAdGroup = this.findById(adgroupId);
        // 时间定向
        Direct formerTimeTypeDirect = directService.findByadGroupId(adgroupId, 2);
        // 地域定向
        Direct formerLocationTypeDirect = directService.findByadGroupId(adgroupId, 1);
        // 处理投放
        if (!adGroup.getMode().equals(formerAdGroup.getMode())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改投放模式" + getModel(formerAdGroup.getMode()) + ">" + getModel(adGroup.getMode()));
            logService.add(log);
        }
        if (!adGroup.getPrice().equals(formerAdGroup.getPrice())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改投放单价" + formerAdGroup.getPrice() + ">" + adGroup.getPrice());
            logService.add(log);
        }
        if (!adGroup.getMaxImpression().equals(formerAdGroup.getMaxImpression())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改曝光总上限" + formerAdGroup.getMaxImpression() + ">" + adGroup.getMaxImpression());
            logService.add(log);
        }
        if (!adGroup.getMaxClick().equals(formerAdGroup.getMaxClick())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改点击总上限" + formerAdGroup.getMaxClick() + ">" + adGroup.getMaxClick());
            logService.add(log);
        }
        if (!adGroup.getDailyMaxImpression().equals(formerAdGroup.getDailyMaxImpression())) {
            log.setAction(
                    "投放：" + adGroup.getAdGroupName() + "修改每日曝光总上限" + formerAdGroup.getDailyMaxImpression() + ">" + adGroup.getDailyMaxImpression());
            logService.add(log);
        }
        if (!adGroup.getDailyMaxClick().equals(formerAdGroup.getDailyMaxClick())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改每日点击总上限" + formerAdGroup.getDailyMaxClick() + ">" + adGroup.getDailyMaxClick());
            logService.add(log);
        }
        if (!adGroup.getPerClickType().equals(formerAdGroup.getPerClickType()) || !adGroup.getPerClick().equals(formerAdGroup.getPerClick())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改单人点击频次" + getType(formerAdGroup.getPerClickType()) + formerAdGroup.getPerClick() + ">"
                    + getType(adGroup.getPerClickType()) + adGroup.getPerClick());
            logService.add(log);
        }
        if (!adGroup.getPerImpression().equals(formerAdGroup.getPerImpression())
                || !adGroup.getPerImpressionType().equals(formerAdGroup.getPerImpressionType())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改单人曝光频次" + getType(formerAdGroup.getPerImpressionType())
                    + formerAdGroup.getPerImpression() + ">" + getType(adGroup.getPerImpressionType()) + adGroup.getPerImpression());
            logService.add(log);
        }
        if (!adGroup.getAdGroupName().equals(formerAdGroup.getAdGroupName())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改投放名称" + formerAdGroup.getAdGroupName() + ">" + adGroup.getAdGroupName());
            logService.add(log);
        }
        if (!adGroup.getDeviceType().equals(formerAdGroup.getDeviceType())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改流量来源" + formerAdGroup.getDeviceType() + ">" + adGroup.getDeviceType());
            logService.add(log);
        }
        if (!adGroup.getBuyType().equals(formerAdGroup.getBuyType())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改交易方式" + formerAdGroup.getBuyType() + ">" + adGroup.getBuyType());
            logService.add(log);
        }
        if (!adGroup.getSpeedMode().equals(formerAdGroup.getSpeedMode())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改投放速度" + formerAdGroup.getSpeedMode() + ">" + adGroup.getSpeedMode());
            logService.add(log);
        }
        if (!adGroup.getDailyBudget().equals(formerAdGroup.getDailyBudget())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改订单日预算" + formerAdGroup.getDailyBudget() + ">" + adGroup.getDailyBudget());
            logService.add(log);
        }
        // 时间定向
        Direct timeDirectAfter = directService.findByadGroupId(adgroupId, 2);
        if (formerTimeTypeDirect != null && timeDirectAfter != null) {
            if (!formerTimeTypeDirect.getBackShow().equals(timeDirectAfter.getBackShow())) {
                log.setAction(
                        "投放：" + adGroup.getAdGroupName() + "修改时间定向显示" + formerTimeTypeDirect.getBackShow() + ">" + timeDirectAfter.getBackShow());
                logService.add(log);
            }
            if (!formerTimeTypeDirect.getData().equals(timeDirectAfter.getData())) {
                log.setAction(
                        "投放：" + adGroup.getAdGroupName() + "修改时间定向内容" + formerTimeTypeDirect.getBackShow() + ">" + timeDirectAfter.getBackShow());
                logService.add(log);
            }
        } else if (formerTimeTypeDirect != null && timeDirectAfter == null) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改时间定向内容" + formerTimeTypeDirect.getBackShow() + "," + formerTimeTypeDirect.getData()
                    + "  >  ");
            logService.add(log);
        } else if (formerTimeTypeDirect == null && timeDirectAfter != null) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改时间定向内容      >" + timeDirectAfter.getBackShow() + "," + timeDirectAfter.getData());
            logService.add(log);
        }
        // 地域定向
        Direct locationDirectAfter = directService.findByadGroupId(adgroupId, 1);
        if (formerLocationTypeDirect != null && locationDirectAfter != null) {
            if (!formerLocationTypeDirect.getBackShow().equals(locationDirectAfter.getBackShow())) {
                log.setAction("投放：" + adGroup.getAdGroupName() + "修改时间定向显示" + formerLocationTypeDirect.getBackShow() + ">"
                        + locationDirectAfter.getBackShow());
                logService.add(log);
            }
            if (!formerLocationTypeDirect.getData().equals(locationDirectAfter.getData())) {
                log.setAction("投放：" + adGroup.getAdGroupName() + "修改时间定向内容" + formerLocationTypeDirect.getBackShow() + ">"
                        + locationDirectAfter.getBackShow());
                logService.add(log);
            }
        } else if (formerLocationTypeDirect != null && locationDirectAfter == null) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改时间定向内容" + formerLocationTypeDirect.getBackShow() + ","
                    + formerTimeTypeDirect.getData() + "  >  ");
            logService.add(log);
        } else if (formerLocationTypeDirect == null && locationDirectAfter != null) {
            log.setAction(
                    "投放：" + adGroup.getAdGroupName() + "修改时间定向内容      >" + locationDirectAfter.getBackShow() + "," + locationDirectAfter.getData());
            logService.add(log);
        }
        //性别、年龄定向
        if (!adGroup.getAge().equals(formerAdGroup.getAge())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改投放年龄定向" + formerAdGroup.getAge() + ">"
                    + adGroup.getAge());
            logService.add(log);
        }
        if (!adGroup.getGender().equals(formerAdGroup.getGender())) {
            log.setAction("投放：" + adGroup.getAdGroupName() + "修改投放性别定向" + formerAdGroup.getGender() + ">"
                    + adGroup.getGender());
            logService.add(log);
        }
        this.edit(adGroup, paramMap, request, account);
        return true;
    }

    // 投放模式（1-CPM,2-CPC）
    private String getModel(Integer i) {
        if (i.equals(1)) {
            return "CPM";
        } else {
            return "CPC";
        }
    }

    // （1-天，2-投放周期）
    private String getType(Integer i) {
        if (i.equals(1)) {
            return "每天";
        } else {
            return "投放周期";
        }
    }

    @Override
    public String queryAdgroupNameById(Long id) {
        return myBatisDao.get("adGroupSqlMapper.queryNameById", id);
    }

    @Override
    public boolean updateAdgroupDateByCondition(List<Long> idList, Date start, Date end) {
        myBatisDao.save("adGroupSqlMapper.updateAdgroupDateBetch",
                MapBuilder.create(HashMap.class).add("idList", idList).add("startDate", start).add("endDate", end).map());
        return true;
    }

    @Override
    public boolean cpoyAdGroup(AdGroup adgroup) {
        myBatisDao.save("adGroupSqlMapper.cpoyAdGroup", adgroup);
        return true;
    }

    /**
     * orderList 要复制到的订单 adgroupList 要复制的策略
     */
    @Override
    public AjaxResult copyAdgroup2Order(List<Long> orderList, List<Long> adgroupList, int type) {
        AjaxResult result = new AjaxResult();
        if (orderList == null || orderList.size() == 0) {
            result.setStatus("ERROR");
            result.setMsg("订单不能为空");
            return result;
        }

        if (adgroupList == null || adgroupList.size() == 0) {
            result.setStatus("ERROR");
            result.setMsg("策略不能为空");
            return result;
        }

        // 1.复制投放
        AdGroup adgroup = null;
        long supdated = System.currentTimeMillis() / 1000;
        // 对每一个订单进行策略copy
        for (long orderId : orderList) {
            adgroup = new AdGroup();
            adgroup.setOrderId(orderId);
            for (long adgroupId : adgroupList) {
                adgroup.setId(adgroupId);
                this.cpoyAdGroup(adgroup);
                this.bannerService.copyBannerBetch(orderId, adgroupId, adgroup.getId(), supdated);
                // 3.查询投放有关的其他东西（地域或时间定向，广告位）
                // 3.1 排期
                // this.adGroupScheduleService.copyAdgroupSchedule(adgroupId,
                // adgroup.getId());
                // 3.1.B 地域或时间定向
                this.directService.copyTargetShow(adgroupId, adgroup.getId());
                // 3.2 广告位
                this.adgroupZoneService.copyAdgroupZone(adgroupId, adgroup.getId());
                // 定量设置 t_adgroup_num
                this.adGroupNumService.copyAdGroupNum(adgroupId, adgroup.getId());
            }
        }
        result.setStatus("OK");
        result.setMsg("策略复制成功");
        return result;
    }

    @Override
    public AdGroup queryAdGroupByOrderId(Long orderId) {
        return myBatisDao.get("adGroupSqlMapper.queryByOrderId", orderId);
    }

    @Override
    public List<AdGroupNum> getAdgroupNumById(Long adGroupId) {
        return myBatisDao.getList("adGroupNumSqlMapper.getAdgroupNumById", adGroupId);
    }

    @Override
    public boolean deleteAdgroupNumById(Long adGroupId) {
        myBatisDao.save("adGroupSqlMapper.deleteAdgroupNumById", adGroupId);
        return true;
    }

    @Override
    public void insertAdGroupNumList(List<AdGroupNum> adGroupNumList) {
        myBatisDao.getList("adGroupSqlMapper.insertAdGroupNumList", MapBuilder.create(HashMap.class).add("adGroupNumList", adGroupNumList).map());
    }

    @Override
    public void updateHtml(AdGroup t) {
        myBatisDao.save("adGroupSqlMapper.updateHtml", t);
    }

    public static void noticeDirectOrder(String url) {
        String message = HttpClienUtil.postJson(url, "");
        Gson gson = new Gson();
        Map msg = gson.fromJson(message, Map.class);
        logger.info("通知" + url + "返回结果：status:" + msg.get("status") + "  msg:" + msg.get("msg"));
    }

    @Override
    public List<CategoryEntity> getCategoryList(String deviceType, SqlServer sqlServer) {
        String sql = "";
        if (deviceType.equals("1") || deviceType.equals("2")) {
            sql = "select value as categoryId,configname as categoryName from config_common where category = 'websitecategory'";
        } else if (deviceType.equals("3")) {
            sql = "select id as categoryId,category as categoryName from config_app_category where fid = 0";
        }
        ResultSet rs = sqlServer.select(sql);
        List<CategoryEntity> categoryList = new ArrayList<CategoryEntity>();
        try {
            categoryList = DBHelper.mapping(rs, CategoryEntity.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return categoryList;
    }

    @Override
    public List<CategoryEntity> getSubCategoryList(Integer categoryId, SqlServer sqlServer) {
        String sql = "select id as categoryId,category as categoryName from config_app_category where fid =" + categoryId;
        ResultSet rs = sqlServer.select(sql);
        List<CategoryEntity> categoryList = new ArrayList<CategoryEntity>();
        try {
            categoryList = DBHelper.mapping(rs, CategoryEntity.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return categoryList;
    }

    @Override
    public Double queryCtrByAdid(Integer adid, String date, SqlServer sqlServer) {
        String sql = "select sum(impressions) as impressions,sum(clicks) as clicks ,adid from report_daily_channel_data where adid = " + adid
                + " and date='" + date + "'";
        double ctr = 0.00d;
        ResultSet rs = sqlServer.select(sql);
        try {
            List<PlatFormParam> params = DBHelper.mapping(rs, PlatFormParam.class);
            PlatFormParam sumParam = params.get(0);
            long impressions = sumParam.getImpressions();
            long clicks = sumParam.getClicks();
            ctr = DoublePreciseCompute.round(impressions == 0 ? 0 : (double) clicks / impressions * 100, 3);
            return ctr;
        } catch (Exception e) {
            e.printStackTrace();
            return 0.0d;
        }
    }

    @Override
    public List<AdsVoEntity> recommendAdsList(Map<String, Object> condition, Long adgroupId, Long dailyMaxClick, Long dailyMaxImpression,
                                              SqlServer sqlServer, String deviceType) {
        Date yesterdayDate = DateUtils.addDay(new Date(), -1);
        String yesterday = DateUtils.getDateToString(DateUtils.DATEFORMATSHORT, yesterdayDate);
        Integer mode = NumberUtils.parseInt(condition.get("mode"));
        List<AdsVoEntity> recommendList = new ArrayList<AdsVoEntity>();

        StringBuffer sql = new StringBuffer("SELECT datas.adid adid,datas.clicks,datas.impressions FROM (select sum(clicks) as clicks,sum(impressions) as impressions,adid ");
        sql.append(" from report_daily_channel_data where date ='");
        sql.append(yesterday);
        sql.append("' GROUP BY adid ) datas ");
        sql.append(" LEFT JOIN management_ads ads on(ads.id = datas.adid) ");
        if (mode == 1) {
            long impressions = Math.round(dailyMaxImpression * BusinessConstants.gap_value * 1000);
            // cpm 结算方式
            sql.append("WHERE datas.impressions <=" + impressions);
            getBannerSqlString(sql, adgroupId);
            sql.append(" ORDER BY datas.impressions DESC LIMIT 10");
        } else if (mode == 2) {
            long click = Math.round(dailyMaxClick * BusinessConstants.gap_value);
            //cpc 结算方式
            sql.append("WHERE datas.clicks <=" + click);
            getBannerSqlString(sql, adgroupId);
            sql.append(" ORDER BY datas.clicks DESC LIMIT 10");
        }
        ResultSet rs = sqlServer.select(sql.toString());
        try {
            List<PlatFormParam> adIdList = DBHelper.mapping(rs, PlatFormParam.class);
            recommendList = getAdsListByIdList(adIdList, condition, deviceType);
        } catch (Exception e) {
            logger.error("get recommend list error : " + e.getMessage());
        }
        return recommendList;
    }

    private List<AdsVoEntity> getAdsListByIdList(List<PlatFormParam> adIdList, Map<String, Object> condition,
                                                 String deviceType) {
        List<AdsVoEntity> adsList = new ArrayList<AdsVoEntity>();
        if (adIdList.size() > 0) {
            condition.put("adIdList", adIdList);
            if (deviceType.equals("1") || deviceType.equals("2")) {
                adsList = websiteService.queryManageAdsByList(condition);
            } else if (deviceType.equals("3")) {
                adsList = websiteService.queryAppAdsByList(condition);
            }
        }
        return adsList;
    }

    @Override
    public void offLineAdgroup() {
        myBatisDao.save("adGroupSqlMapper.offLineAdgroup", null);
    }

    private StringBuffer getBannerSqlString(StringBuffer sql, Long adgroupId) {
        StringBuffer widthStr = new StringBuffer();
        StringBuffer heightStr = new StringBuffer();
        // 获取宽、高数组
        List<Banner> bannerList = bannerService.getBannerListByAdGroupId(adgroupId);
        if (bannerList.size() > 0) {
            widthStr.append(" and ads.width in(");
            heightStr.append(" and ads.height in(");
            for (Banner banner : bannerList) {
                widthStr.append(banner.getBannerTemplate().getWidth());
                widthStr.append(",");
                heightStr.append(banner.getBannerTemplate().getHeight());
                heightStr.append(",");
            }
            widthStr.append(")");
            heightStr.append(")");
            widthStr.deleteCharAt(widthStr.length() - 2);
            heightStr.deleteCharAt(heightStr.length() - 2);
        }
        sql.append(widthStr);
        sql.append(heightStr);
        return sql;
    }

    @Override
    public void updateIsEdit(AdGroup t) {
        myBatisDao.save("adGroupSqlMapper.updateIsEdit", t);
    }
}